#pragma once
#include "stdafx.h"
#include "CheckFitness.h"
#include "GbcParser.h"
#include "CornerDetect.h"
#include <string>
#include <set>
#include <list>

int SNU_g_anWhitePixelCnt[NUM_OF_BILLTYPES][NUM_OF_BILLDIRECTION][2][SNU_GBC_IMAGE_WIDTH*SNU_GBC_IMAGE_HEIGHT];
int SNU_g_anTotalCase[NUM_OF_BILLTYPES][NUM_OF_BILLDIRECTION][2];

static const int SNU_WHITE_THRESHHOLD = 190;
static const int SNU_GRAFFITI_THRESH_HOLD = 90;
static const int SNU_GRAFFITI_GRIDSIZE = 15;
std::set<std::pair<int,int>> SNU_g_asetWhiteAreas[NUM_OF_BILLTYPES][NUM_OF_BILLDIRECTION][2];
std::list<std::pair<int,int>> SNU_g_alistWhiteAreas[NUM_OF_BILLTYPES][NUM_OF_BILLDIRECTION][2];

void SNU_LearnGraffitiData(const CString& strPath, int nBillType, int nBillDirection, int nImageNum)
{
	bool bRet = false;
	char** ppImageArrays = NULL;
	do
	{
		int nSum = 0;
        
		ppImageArrays = SNU_allocate_image_array();

		if ( !SNU_parse_gbc(strPath, ppImageArrays) )
			break;

		int nWidth=0, nHeight=0;
        CCornerInfo* pCornerInfo = SNU_detect_corner_norotate(ppImageArrays);
		if ( !pCornerInfo )
			break;

		for ( int x=0; x<pCornerInfo->GetWidth(); x++ )
		{
			for ( int y=0; y<pCornerInfo->GetHeight(); y++ )
			{
				BYTE nCurVal = ppImageArrays[nImageNum*4][pCornerInfo->GetConverted(std::pair<int,int>(x,y),nImageNum*4)];
				if ( nCurVal > SNU_WHITE_THRESHHOLD )
				{
					SNU_g_anWhitePixelCnt[nBillType][nBillDirection][nImageNum][SNU_TO_ARRAY_INDEX(x,y)]++;
				}
			}
		}
		SNU_g_anTotalCase[nBillType][nBillDirection][nImageNum]++;
		
        delete pCornerInfo;
		bRet = true;
	} while(0);

    SNU_free_image_array(ppImageArrays);

}

void SNU_LearGraffitiData_Recursively(const CString& strPath, int nBillType, int nBillDirection)
{
    CFileFind finder;
    BOOL bWorking = finder.FindFile(strPath + _T("\\*.*"));

    while (bWorking)
    {
        bWorking = finder.FindNextFile();

        if (finder.IsDots())
            continue;

        if (finder.IsDirectory())
        {
            CString strDirPath = finder.GetFilePath();
            SNU_LearGraffitiData_Recursively(strDirPath, nBillType, nBillDirection);
        }
        else
        {
            CString strFilePath = finder.GetFilePath();
            if ( strFilePath.Right(4).CompareNoCase(_T(".gbc")) == 0 )
            {
				bool bDone = true;
				for ( int i=0; i<8; i++ )
				{
					double dRet = 0;
					SNU_LearnGraffitiData(strFilePath, nBillType, nBillDirection, 0);
					SNU_LearnGraffitiData(strFilePath, nBillType, nBillDirection, 1);
				}
            }
        }
    }
    finder.Close();
}

bool SNU_PrepareGraffitiTest()
{
	for ( int i=0; i<NUM_OF_BILLTYPES; i++ )
		for ( int j=0; j<NUM_OF_BILLDIRECTION; j++ )
			for ( int k=0; k<2; k++ )
			{
				SNU_g_anTotalCase[i][j][k]=0;
				for ( int x=0; x<SNU_GBC_IMAGE_WIDTH; x++ )
					for ( int y=0; y<SNU_GBC_IMAGE_HEIGHT; y++ )
						SNU_g_anWhitePixelCnt[i][j][k][SNU_TO_ARRAY_INDEX(x,y)] = 0;
			}

	CString strRootPath = _T("D:\\billchecker\\Samples\\_NEW");
	for ( int nBillDirection=0; nBillDirection<NUM_OF_BILLDIRECTION; nBillDirection++ )
	{
		CString strBillDirection;
		switch ( nBillDirection )
		{
		case BILLDIRECTION_FT : strBillDirection = _T("FT"); break;
		case BILLDIRECTION_FB : strBillDirection = _T("FB"); break;
		case BILLDIRECTION_BT : strBillDirection = _T("BT"); break;
		case BILLDIRECTION_BB : strBillDirection = _T("BB"); break;
		}
		if ( strBillDirection.IsEmpty() ) 
			continue;
		CString strPath;
		strPath.Format(_T("%s\\%s"), strRootPath, strBillDirection);
		SNU_LearGraffitiData_Recursively(strPath, BILLTYPE_YUAN_50, nBillDirection);

		for ( int k=0; k<2; k++ )
		{
			for ( int x=3; x<SNU_GBC_IMAGE_WIDTH-3; x+=SNU_GRAFFITI_GRIDSIZE )
				for ( int y=3; y<SNU_GBC_IMAGE_HEIGHT-3; y+=SNU_GRAFFITI_GRIDSIZE )
				{
					int sum = 0;
					for ( int dx = -3; dx <= 3; dx++ )
						for ( int dy=-3; dy<=3; dy++ )
							sum += SNU_g_anWhitePixelCnt[BILLTYPE_YUAN_50][nBillDirection][k][SNU_TO_ARRAY_INDEX((x+dx),(y+dy))];
					if ( sum*100 > SNU_g_anTotalCase[BILLTYPE_YUAN_50][nBillDirection][k]*49*SNU_GRAFFITI_THRESH_HOLD )
					{
						for ( int dx = -3; dx <= 3; dx+=3 )
							for ( int dy=-3; dy<=3; dy+=3 )
							SNU_g_asetWhiteAreas[BILLTYPE_YUAN_50][nBillDirection][k].insert(std::pair<int,int>(x+dx,y+dy));
					}
				}
		}
	}

	for ( int i=0; i<NUM_OF_BILLTYPES; i++ )
		for ( int j=0; j<NUM_OF_BILLDIRECTION; j++ )
			for ( int k=0; k<2; k++ )
				for ( std::set<std::pair<int,int>>::iterator iter=SNU_g_asetWhiteAreas[i][j][k].begin(); iter!=SNU_g_asetWhiteAreas[i][j][k].end(); iter++ )
					SNU_g_alistWhiteAreas[i][j][k].push_back(*iter);

	return true;
}

bool SNU_InitGraffitiTestData_FromFile(const std::string& strOutfilePath)
{
	FILE* pFile = fopen(strOutfilePath.c_str(), "r");
	if ( pFile )
	{
		int nCaseNum = 0;
		fscanf(pFile, "%d", &nCaseNum);
		for ( int i=0; i<nCaseNum; i++ )
		{
			int nBillType, nBillDirection, nImageNum, nPointNum;
			fscanf(pFile, "%d %d %d %d", &nBillType, &nBillDirection, &nImageNum, &nPointNum);
			for ( int j=0; j<nPointNum; j++ )
			{
				int x, y;
				fscanf(pFile, "%d %d", &x, &y);
				SNU_g_alistWhiteAreas[nBillType][nBillDirection][nImageNum].push_back(std::pair<int,int>(x,y));
			}
		}
		fclose(pFile);
		return true;
	}
	else
		return false;
}

bool SNU_SerializeGraffitiTestData_ToFile(const std::string& strOutfilePath)
{
	FILE* pFile = fopen(strOutfilePath.c_str(), "w");
	if ( pFile )
	{
		fprintf(pFile,"%d\n", NUM_OF_BILLTYPES*NUM_OF_BILLDIRECTION*2);
		for ( int i=0; i<NUM_OF_BILLTYPES; i++ )
			for ( int j=0; j<NUM_OF_BILLDIRECTION; j++ )
				for ( int k=0; k<2; k++ )
				{
					fprintf(pFile,"%d %d %d %d\n", i, j, k, SNU_g_alistWhiteAreas[i][j][k].size());
					for ( std::list<std::pair<int,int>>::iterator iter=SNU_g_alistWhiteAreas[i][j][k].begin();
						iter!=SNU_g_alistWhiteAreas[i][j][k].end(); iter++ )
					{
						fprintf(pFile,"%d %d ", iter->first, iter->second);
					}
					fprintf(pFile,"\n");
				}
		fclose(pFile);
		return true;
	}
	else
		return false;
}

bool SNU_PREPROCESS_GRAFFITI() 
{
	//SNU_PrepareGraffitiTest();
	//SNU_SerializeGraffitiTestData_ToFile("graffiti_data");
	SNU_InitGraffitiTestData_FromFile("graffiti_data");

	return true;
}

bool SNU_CHECK_FITNESS_GRAFFITI(char** ppImageArrays, CCornerInfo* pCornerInfo, int nBillType, int nBillDirection) 
{
	int anSum[2] = {0,0};
	int anAll[2] = {0,0};

	for ( int k=0; k<2; k++ )
		for ( std::list<std::pair<int,int>>::iterator iter=SNU_g_alistWhiteAreas[nBillType][nBillDirection][k].begin();
				iter!=SNU_g_alistWhiteAreas[nBillType][nBillDirection][k].end(); iter++ )	
		{
			BYTE nCurVal = ppImageArrays[k*4][pCornerInfo->GetConverted(std::pair<int,int>(iter->first, iter->second),k*4)];
			if ( nCurVal > SNU_WHITE_THRESHHOLD )
			{
				anSum[k] ++;
			}
			anAll[k] ++;
		}

	return (anSum[0] * 100 >= anAll[0] * 80) && (anSum[1] * 100 >= anAll[1] * 80);
}
